package com.example.h5server.utils;


public class SnowflakeIdUtil {

    // 起始时间戳 (2025-01-01)
    private static final long START_TIMESTAMP = 1798761600000L;

    // 各部分位数
    private static final long SEQUENCE_BIT = 12;
    private static final long MACHINE_BIT = 5;
    private static final long DATA_CENTER_BIT = 5;

    // 最大值
    private static final long MAX_SEQUENCE = ~(-1L << SEQUENCE_BIT);

    // 位移量
    private static final long MACHINE_LEFT = SEQUENCE_BIT;
    private static final long DATA_CENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
    private static final long TIMESTAMP_LEFT = DATA_CENTER_LEFT + DATA_CENTER_BIT;

    private long dataCenterId;  // 数据中心ID
    private long machineId;     // 机器ID
    private long sequence = 0L; // 序列号
    private long lastTimestamp = -1L; // 上次时间戳

    public SnowflakeIdUtil(long dataCenterId, long machineId) {
        if (dataCenterId > ~(-1L << DATA_CENTER_BIT) || dataCenterId < 0) {
            throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATA_CENTER_NUM or less than 0");
        }
        if (machineId > ~(-1L << MACHINE_BIT) || machineId < 0) {
            throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0");
        }
        this.dataCenterId = dataCenterId;
        this.machineId = machineId;
    }

    /**
     * 生成雪花ID并转换为8位字符串（取低36位）
     * @return 8位字符串
     */
    public synchronized String generateInviteCode() {
        long currentTime = System.currentTimeMillis();

        if (currentTime < lastTimestamp) {
            throw new RuntimeException("Clock moved backwards. Refusing to generate id");
        }

        if (currentTime == lastTimestamp) {
            sequence = (sequence + 1) & MAX_SEQUENCE;
            if (sequence == 0) {
                currentTime = getNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0L;
        }

        lastTimestamp = currentTime;

        long id = (currentTime - START_TIMESTAMP) << TIMESTAMP_LEFT
                | dataCenterId << DATA_CENTER_LEFT
                | machineId << MACHINE_LEFT
                | sequence;

        // 取低36位并转换为8位字符串
        return convertTo8CharString(id & ((1L << 36) - 1));
    }

    /**
     * 将数字转换为8位字符串
     * @param id 需要转换的数字
     * @return 8位字符串
     */
    private String convertTo8CharString(long id) {
        // 使用36进制(0-9,a-z)表示，刚好可以表示36位中的每4位
        return String.format("%08d", id % 100000000);
    }

    private long getNextMillis(long lastTimestamp) {
        long timestamp = System.currentTimeMillis();
        while (timestamp <= lastTimestamp) {
            timestamp = System.currentTimeMillis();
        }
        return timestamp;
    }
}
